package com.aube.plugin.guide;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.aube.plugin.origin.R;
import com.huyn.baseframework.dynamicload.CanCloseLayout;
import com.huyn.baseframework.dynamicload.DLLayout;
import com.huyn.baseframework.dynamicload.IPositionManager;
import com.huyn.baseframework.utils.SysUtil;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by huyaonan on 16/8/30.
 */
public class VideoGuideLayout extends DLLayout implements CanCloseLayout {

    /**
     * Mask color
     */
    private int maskColor = 0xa0000000;

    /**
     * VideoGuideLayout will start
     * showing after delayMillis seconds
     * passed
     */
    private long delayMillis;

    /**
     * We don't draw VideoGuideLayout
     * until isReady field set to true
     */
    private boolean isReady;

    /**
     * Show/Dismiss VideoGuideLayout
     * with fade in/out animation if
     * this is enabled.
     */
    private boolean isFadeAnimationEnabled;

    /**
     * Animation duration
     */
    private long fadeAnimationDuration = 700;

    /**
     * rectShape focus on target
     * and clear rect to focus
     */
    private DoubleRect rectShape;

    /**
     * Target View
     */
    private Target targetView;

    private Target mainView;

    /**
     * Handler will be used to
     * delay VideoGuideLayout
     */
    private Handler handler;

    /**
     * All views will be drawn to
     * this bitmap and canvas then
     * bitmap will be drawn to canvas
     */
    private Bitmap bitmap;
    private Canvas canvas;

    /**
     * Layout width/height
     */
    private int width;
    private int height;

    /**
     * Info dialog view
     */
    private View infoView;

    /**
     * Info ImageView
     */
    private ImageView targetImg, tipsImg;

    /**
     * When layout completed, we set this true
     * Otherwise onGlobalLayoutListener stuck on loop.
     */
    private boolean isLayoutCompleted;

    private int displayTime = 0;

    private AtomicBoolean mIsAnimating = new AtomicBoolean(false);

    private OnDismissListener onDismissListener;

    public VideoGuideLayout(Context context) {
        this(context, null);
    }

    public VideoGuideLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VideoGuideLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void initViews() {
        setWillNotDraw(false);
        setVisibility(INVISIBLE);

        /**
         * set default values
         */
        isReady = false;
        isFadeAnimationEnabled = true;
        isLayoutCompleted = false;

        /**
         * initialize objects
         */
        handler = new Handler();

        infoView = inflate(R.layout.guide_layout, null, false);

        targetImg = (ImageView) infoView.findViewById(R.id.guide_target);
        tipsImg = (ImageView) infoView.findViewById(R.id.guide_tips);

        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                rectShape.reCalculateAll();
                if (rectShape != null && rectShape.getPoint().y != 0 && !isLayoutCompleted) {
                    setInfoLayout();
                    removeOnGlobalLayoutListener(VideoGuideLayout.this, this);
                }
            }
        });
    }

    @Override
    public void fillData(Object o) {

    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener){
        if (Build.VERSION.SDK_INT < 16) {
            v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
        } else {
            v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        width = getMeasuredWidth();
        height = getMeasuredHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (!isReady) return;

        if (bitmap == null || canvas == null) {
            if (bitmap != null) bitmap.recycle();

            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            this.canvas = new Canvas(bitmap);
        }

        /**
         * Draw mask
         */
        this.canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        this.canvas.drawColor(maskColor);

        canvas.drawBitmap(bitmap, 0, 0, null);
    }

    /**
     * Shows material view with fade in
     * animation
     *
     * @param activity
     */
    public void show(Activity activity) {
        ((ViewGroup) activity.getWindow().getDecorView()).addView(this);

        isReady = true;

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (isFadeAnimationEnabled) {
                    if(mIsAnimating.get())
                        return;
                    mIsAnimating.set(true);
                    AnimationFactory.animateFadeIn(VideoGuideLayout.this, fadeAnimationDuration, new AnimationListener.OnAnimationStartListener() {
                        @Override
                        public void onAnimationStart() {
                            setVisibility(VISIBLE);
                            mIsAnimating.set(false);
                        }
                    });
                } else
                    setVisibility(VISIBLE);
            }
        },delayMillis);

        if(displayTime > 0) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    dismiss();
                }
            }, delayMillis + displayTime);
        }
    }

    /**
     * Dismiss Material Intro View
     */
    public void dismiss() {
        if(mIsAnimating.get())
            return;
        if(onDismissListener != null)
            onDismissListener.onDismiss();
        mIsAnimating.set(true);
        handler.removeCallbacksAndMessages(null);
        AnimationFactory.animateFadeOut(this, fadeAnimationDuration, new AnimationListener.OnAnimationEndListener() {
            @Override
            public void onAnimationEnd() {
                mIsAnimating.set(false);
                setVisibility(GONE);
                removeMaterialView();
            }
        });
    }

    private void removeMaterialView(){
        if(getParent() != null )
            ((ViewGroup) getParent()).removeView(this);
    }

    /**
     * locate info card view above/below the
     * circle. If circle's Y coordiante is bigger than
     * Y coordinate of root view, then locate cardview
     * above the circle. Otherwise locate below.
     */
    private void setInfoLayout() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                isLayoutCompleted = true;

                if (infoView.getParent() != null)
                    ((ViewGroup) infoView.getParent()).removeView(infoView);

                addView(infoView, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
                infoView.setVisibility(VISIBLE);

                setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if(step == 1 || step == 2) {
                            if(mIsAnimating.get())
                                return;
                            mIsAnimating.set(true);
                            ValueAnimator anim = ValueAnimator.ofFloat(1f, 0f);
                            anim.setDuration(300);
                            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                                @Override
                                public void onAnimationUpdate(ValueAnimator animation) {
                                    float value = (float) animation.getAnimatedValue();
                                    targetImg.setAlpha(value);
                                    tipsImg.setAlpha(value);
                                }
                            });
                            anim.addListener(new AnimatorListenerAdapter() {
                                @Override
                                public void onAnimationEnd(Animator animation) {
                                    step++;
                                    mIsAnimating.set(false);
                                    displayGuide();
                                }
                            });
                            anim.start();
                        } else {
                            dismiss();
                        }
                    }
                });
                displayGuide();
            }
        });
    }

    private int step=1;
    private void displayGuide() {
        if(step == 1) {
            RelativeLayout.LayoutParams targetParams = (RelativeLayout.LayoutParams) targetImg.getLayoutParams();
            Rect rect = rectShape.getRect();
            int marginTop = rect.top;
            int marginLeft = rect.left;
            targetParams.setMargins(marginLeft, marginTop, 0, 0);
            targetParams.width = rect.right - rect.left;
            targetParams.height = rect.bottom - rect.top;

            targetImg.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.guide_djtvideo));

            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.guide_djt);
            int tipsHeight = width * bitmap.getHeight() / bitmap.getWidth();
            RelativeLayout.LayoutParams tipsParams = (RelativeLayout.LayoutParams) tipsImg.getLayoutParams();
            tipsParams.width = (int) (width*0.8f);
            tipsParams.height = (int) (tipsHeight*0.8f);
            tipsImg.setImageBitmap(bitmap);
            tipsImg.setTranslationX(width*0.1f);
            tipsImg.setTranslationY(marginTop - tipsHeight*0.8f - SysUtil.getStatusBarHeight(getContext()));
        } else if(step == 2) {
            targetImg.setVisibility(GONE);
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.guide_guess);
            int tipsHeight = width * bitmap.getHeight() / bitmap.getWidth();
            RelativeLayout.LayoutParams tipsParams = (RelativeLayout.LayoutParams) tipsImg.getLayoutParams();
            tipsParams.width = (int) (width*0.8f);
            tipsParams.height = (int) (tipsHeight*0.8f);
            tipsImg.setLayoutParams(tipsParams);
            tipsImg.setImageBitmap(bitmap);
            tipsImg.setTranslationY((height - tipsHeight*0.8f)/2);
            tipsImg.setTranslationX(width*0.1f);

            mIsAnimating.set(true);
            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
            anim.setDuration(300);
            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    tipsImg.setAlpha(value);
                    mIsAnimating.set(false);
                }
            });
            anim.start();
        } else {
            targetImg.setVisibility(GONE);
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.guide_buy);
            int tipsHeight = width * bitmap.getHeight() / bitmap.getWidth();
            RelativeLayout.LayoutParams tipsParams = (RelativeLayout.LayoutParams) tipsImg.getLayoutParams();
            tipsParams.width = (int) (width*0.8f);
            tipsParams.height = (int) (tipsHeight*0.8f);
            tipsImg.setLayoutParams(tipsParams);
            tipsImg.setImageBitmap(bitmap);
            tipsImg.setTranslationY((height - tipsHeight*0.8f)/2);
            tipsImg.setTranslationX(width*0.1f);

            mIsAnimating.set(true);
            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
            anim.setDuration(300);
            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    tipsImg.setAlpha(value);
                    mIsAnimating.set(false);
                }
            });
            anim.start();
        }
    }


    /**
     * SETTERS
     */

    public void setDelay(int delayMillis) {
        this.delayMillis = delayMillis;
    }

    public void enableFadeAnimation(boolean isFadeAnimationEnabled) {
        this.isFadeAnimationEnabled = isFadeAnimationEnabled;
    }

    private void setTarget(Target target) {
        targetView = target;
    }

    private void setMainView(Target main) {
        mainView = main;
    }

    private void setRect(DoubleRect rectShape) {
        this.rectShape = rectShape;
    }

    public void setOnDismissListener(OnDismissListener listener) {
        this.onDismissListener = listener;
    }

    public void buildRect(View target, View main) {
        setTarget(new ViewTarget(target));
        setMainView(new ViewTarget(main));
        setRect(new DoubleRect(targetView, mainView));
    }

    @Override
    public void notifyAnim(int i) {

    }

    @Override
    public void registToManager(IPositionManager iPositionManager) {

    }

    @Override
    public void unreistFromManager(IPositionManager iPositionManager) {

    }

    @Override
    public int[] getLocations() {
        return new int[0];
    }

    @Override
    public boolean onKeyDownEvent(int keyCode, KeyEvent keyEvent) {
        if(keyCode == KeyEvent.KEYCODE_BACK) {
            if(getVisibility() == VISIBLE) {
                dismiss();
                return true;
            }
        }
        return false;
    }

    public interface OnDismissListener {
        public void onDismiss();
    }

}
